package com.wtgroup.demo.common.judge;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author 60906
 * @date 2021/5/13 15:01
 */
@Accessors(chain = true)
public class Judger {
    private volatile boolean running = false;
    /**
     * 迭代次数 , 默认 1000
     */
    @Setter
    @Getter
    private int iterCount;

    transient private JudgeStatInfo judgeInfo;

    // private Supplier<T> supplyResult1;
    // private Supplier<T> supplyResult2;
    // private BiFunction<T, T, Boolean> comparing;
    /**
     * 一个比较用例不等, 即退出. 默认 true.
     */
    @Setter
    @Getter
    private boolean failFast;
    /**
     * 处理
     */
    @Setter
    @Getter
    private Supplier<Boolean> process;
    private Function<Integer, Boolean> processWithArg;

    public static Judger of(Supplier<Boolean> process) {
        return new Judger(process);
    }
    public static Judger ofi(Function<Integer, Boolean> process) {
        Judger judger = new Judger(null);
        judger.processWithArg = process;
        return judger;
    }

    public Judger(Supplier<Boolean> process) {
        this(1000, process, true);
    }

    public Judger(int iterCount, Supplier<Boolean> process) {
        this(iterCount, process, true);
    }

    public Judger(int iterCount, Supplier<Boolean> process, boolean failFast) {
        this.iterCount = iterCount;
        this.failFast = failFast;
        this.process = process;
    }

    // public Judger(Supplier<T> supplyResult1, Supplier<T> supplyResult2) {
    //     this(1000, supplyResult1, supplyResult2, (r1, r2) -> {
    //         if (r1 == null && r2 == null) {
    //             return true;
    //         }
    //         if (r1 == null || r2 == null) {
    //             return false;
    //         }
    //         return r1.equals(r2);
    //     });
    // }

    // public Judger(int iterationCount, Supplier<T> supplyResult1, Supplier<T> supplyResult2, BiFunction<T, T, Boolean> comparing) {
    //     this.iterationCount = iterationCount;
    //     this.supplyResult1 = supplyResult1;
    //     this.supplyResult2 = supplyResult2;
    //     this.comparing = comparing;
    // }


    public Judger start() {
        if (running == true) {
            return this;
        }
        running = true;
        int ok = 0;
        int fail = 0;
        int i = 0;
        for (; i < iterCount; i++) {
            // T r1 = supplyResult1.get();
            // T r2 = supplyResult2.get();
            // if (! comparing.apply(r1, r2)) {
            //     fail++;
            //     if (this.failFast) {
            //         i--;
            //         break;
            //     }
            // }

            boolean t = false;
            try {
                if (process != null) {
                    t = this.process.get();
                } else if (processWithArg != null) {
                    t = this.processWithArg.apply(i);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (t) {
                ok++;
            } else {
                fail++;
                if (this.failFast) {
                    i++;
                    break;
                }
            }
        }

        JudgeStatInfo info = new JudgeStatInfo();
        info.process = i;
        info.fail = fail;
        info.success = ok;

        this.judgeInfo = info;

        return this;
    }

    public void print() {
        System.out.println(this.judgeInfo);
    }

    static class JudgeStatInfo {
        int success;
        int fail;
        int process;

        @Override
        public String toString() {
            return "success: " + success +
                    ", fail: " + fail +
                    ", process: " + process;
        }
    }
}
